package IO;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

public class Demo5_OtherStream {

    /**
     * 序列化流/对象流
     *   如果想把一个类的实例化对象写入文件，需要用到对象流
     *   对象不是文本，不能使用字符流，只能使用字节流
     *
     * 序列化/反序列化
     *   把对象从内存以字节数组的形式写入磁盘的过程就是序列化的过程
     *   字节数组形式的对象从磁盘读到内存的过程就是反序列化的过程
     *
     *   写入文件的所有数据都必须可以做序列化/反序列操作
     *   写入文件的对象所对应的类必须实现Serializable接口(标记接口)
     */
    public static void objectStreamTest() throws Exception {

        List<Student> list_stus = new ArrayList<>();

        //创建一个任何类的实例化对象
        list_stus.add(new Student("tom",10));
        list_stus.add(new Student("jerry",20));
        list_stus.add(new Student("kitty",60));
        list_stus.add(new Student("小开开",30));
        list_stus.add(new Student("小俊俊",50));



        //创建一个对象输出字节流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D://student.txt"));

        oos.writeObject(list_stus);

        oos.close();


        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D://student.txt"));

        List<Student> stuGet = (List<Student>)ois.readObject();

        for (Student student : stuGet) {
            System.out.println(student.getName());
            System.out.println(student.getAge());
            System.out.println("==================================");
        }

        ois.close();

    }

    /**
     * 打印流
     *   print
     *   打印即为输出，打印流就是输出流
     * 字节打印流
     * 字符打印流
     */
    public static void printStreamTest() throws Exception {
        //创建一个字节打印流
        PrintStream ps_stream = new PrintStream("D://printStream.txt");
        PrintWriter ps_writer = new PrintWriter("D://printWriter.txt");

        ps_writer.print("哈哈哈");
        ps_writer.print(true);
        ps_writer.println();
        ps_writer.println(123456789);
        ps_writer.println(new Student("tom",100));

        ps_writer.flush();
        ps_writer.close();
    }

    /**
     * Properties
     *   是Map接口的一个实现类，存储的是键值对形式的数据
     * Properties一般可以作为一个配置文件的形式与流整合使用
     *
     * 好处：
     *   可以把代码中的一些相对固定的信息写在配置文件中，通过读取文件获取内容
     *   避免修改内容的时候，重新编译代码
     */
    public static void propertiesTest() throws Exception {

        //properties作为集合的基本使用
//        Properties properties = new Properties();
//        properties.setProperty("name","tom");
//        properties.setProperty("age","100");
//
//        System.out.println(properties.getProperty("name"));
//        Set<String> strings = properties.stringPropertyNames();
//        for (String string : strings) {
//            System.out.println(string);
//        }

        //Properties与流整合
        Properties prop = new Properties();

        //把properties集合中的键值对写入配置文件
        prop.setProperty("url","qweer");
        prop.setProperty("driver","com");
        //comments参数表示注释，没有意义
        //如果新添加的内容key相同，value会被覆盖，properties遵循Map的特性
        prop.store(new FileOutputStream("D://aaa.txt",true),"test");

        //把配置文件的内容以字节输入流的形式加载到当前集合中
        prop.load(new FileInputStream("D://aaa.txt"));

        //把从配置文件中读取的信息输出
        Set<String> connectInfo = prop.stringPropertyNames();
        for (String info : connectInfo) {
            System.out.println(info+"==="+prop.getProperty(info));
        }

    }


    /**
     * 转换流
     *   在读或写的过程把字节转换成字符的流
     *   原理就是 字符 = 字节 + 字符编码表
     * 字节输入转换流
     *   在输入阶段把字节转成字符
     * 字节输出转换流
     *   在输出阶段把字节转成字符
     *
     * 注意：不管是读还是写，毕竟设计到字节转字符，编码和解码的字符集一定要保持一致
     */
    public static void transformStreamTest() throws Exception {

        FileInputStream fis = new FileInputStream("D://copy.txt");
        FileOutputStream fos = new FileOutputStream("D://copy.txt");

        //创建一个输入字节转换流
        InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
        OutputStreamWriter osr = new OutputStreamWriter(fos,"GBK");


        osr.write("你好");
        osr.flush();

        int temp;
        while ((temp=isr.read())!=-1){
            System.out.println((char)temp);
        }

        isr.close();
        fis.close();
        osr.close();
        fos.close();



    }


    public static void main(String[] args) throws Exception {
//        Demo5_OtherStream.objectStreamTest();
//        Demo5_OtherStream.printStreamTest();
//        Demo5_OtherStream.propertiesTest();

//        Demo5_OtherStream.transformStreamTest();

    }

}


class Student implements Serializable {

    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
